import {MangaSite} from "../MangaSite";
import {requestText} from "../../../function/httpFunc";
import {exists, getAppDirPath, joinPath, readFile, writeFile} from "../../../function/fileFunc";
import {message} from "antd";
// import {parseImgList} from "./parseImgList";
export namespace GanGanOnline {
    interface ImgInfoBase {
        src: string;
        isLink: boolean;
    }
    export interface ImgInfoMain extends ImgInfoBase {
        isLink: false;
        secretKey: string;
    }
    export interface ImgInfoLink extends ImgInfoBase {
        isLink: true;
        linkURL: string;
    }
    export type ImgInfo = ImgInfoMain | ImgInfoLink;
    export interface ImgItemInfoLink extends MangaSite.ImgItemInfo, ImgInfoLink {
    }
    export interface ImgItemInfoMain extends MangaSite.ImgItemInfo, ImgInfoMain {
    }
    export type ImgItemInfo = ImgItemInfoLink | ImgItemInfoMain;
}

export class GanGanOnline extends MangaSite {
    public drawPage(
        img: HTMLImageElement,
        position?: MangaSite.TDrawPosition,
        showPageIndexLen?: number
    ): this {
        this.directDrawPage(img, position, showPageIndexLen);
        return this;
    }
    public async getImgList(): Promise<GanGanOnline.ImgItemInfo[]> {
        const data = await this.getJSON();
        return JSON.parse(data) as GanGanOnline.ImgItemInfo[];
    }
    public parseImgList(parseData: string): GanGanOnline.ImgInfo[] {
        const reg = /[^A-Za-z0-9*_.&=+\-\/#@$?:]/mg;
        const newStr = parseData
            .replace(reg, " ")
            .replace(/\s+/g, "\n");

        const list = newStr.split("\n").filter((str) => {
            return !!str;
        });
        const dataList: GanGanOnline.ImgInfoMain[] = [];
        for (let i = 0; i < list.length / 2; i++) {
            dataList[i] = {
                src: "",
                isLink: false,
                secretKey: "",
            };
        }
        list.forEach((str, strIndex) => {
            const dataIndex = Math.floor(strIndex / 2);
            const dataObjKey = strIndex % 2 ? "secretKey" : "src";
            (dataList[dataIndex] as GanGanOnline.ImgInfoMain)[dataObjKey] = str;
        });
        return this.getRuledListFrom(dataList);
    }
    protected getRuledListFrom(originList: GanGanOnline.ImgInfoMain[]): GanGanOnline.ImgInfo[] {
        return originList.map((item) => {
            const that = this;
            const linkURL = that.getLinkUrlSrc(item.src);
            if (linkURL.isLink) {
                return {
                    src: linkURL.src,
                    isLink: true,
                    linkURL: that.getLinkURLFrom(item.secretKey),
                } as GanGanOnline.ImgInfo;
            }
            return item as GanGanOnline.ImgInfo;
        }).filter((item) => {
            return this.isURL(item.src);
        });
    }
    protected isURL(str: string): boolean {
        return /^http(s?):\/\//.test(str);
    }
    protected getLinkURLFrom(src: string): string {
        const result = src.match(/http(.+)$/);
        if (result) {
            return result[0];
        }
        return src;
    }
    protected getLinkUrlSrc(str: string) {
        const result = str.match(/^z(.+)/);
        if (result) {
            return {
                isLink: true,
                src: result[1],
            };
        }
        return {
            isLink: false,
        };
    }
    protected async cacheArticleInfoJSONFile(filename: string): Promise<string> {
        const reqData = await requestText( this.articleInfo.origin_url, "utf8", "POST");
        const imgList = this.reqDataToImgList(reqData);
        const data = JSON.stringify(imgList);
        await writeFile(filename, data);
        return Promise.resolve(data);
    }
    protected reqDataToImgList(data: string): GanGanOnline.ImgItemInfo[] {
        return this.parseImgList(data).map((item, index) => {
            if (item.isLink) {
                return {
                    imgIndex: (index + 1),
                    src: item.src,
                    type: "GanGanOnline",
                    isLink: true,
                    linkURL: item.linkURL,
                };
            }
            return {
                imgIndex: (index + 1),
                src: item.src,
                type: "GanGanOnline",
                isLink: false,
                secretKey: (item as GanGanOnline.ImgInfoMain).secretKey,
            };
        });
    }
    protected async loadImgFromTmp(
        imgInfo: GanGanOnline.ImgItemInfo,
        img?: HTMLImageElement
    ): Promise<HTMLImageElement> {
        if (imgInfo.isLink) {
            return this.loadLinkImgFromTmp(imgInfo, img);
        }
        return this.loadMainImgFromTmp(imgInfo as GanGanOnline.ImgItemInfoMain, img)
            .then((imgElm) => {
                this.setImgElmCacheItem(imgInfo.src, imgElm);
                return imgElm;
            });
    }
    protected loadLinkImgFromTmp(
        imgInfo: GanGanOnline.ImgItemInfoLink,
        img?: HTMLImageElement
    ): Promise<HTMLImageElement> {
        return super.loadImgFromTmp(imgInfo, img);
    }
    protected async loadMainImgFromTmp(
        imgInfo: GanGanOnline.ImgItemInfoMain,
        img?: HTMLImageElement
    ): Promise<HTMLImageElement> {
        const relName = this.getPicRelName(imgInfo.imgIndex);
        const parsedRelName = relName + ".parsed.jpg";
        const parsedSrc = "akaba:///tmp/" + parsedRelName;
        const localParsedRelName = joinPath(getAppDirPath(), "tmp", parsedRelName);
        const parsedSrcExists = await exists(localParsedRelName);
        if (parsedSrcExists) {
            console.log("load main parsed img: " + imgInfo.src);
            return this.buildImgFrom(parsedSrc, imgInfo.type, img);
        }
        return this.resetSuperLoadImgFromTmp(imgInfo, img);
    }
    protected resetSuperLoadImgFromTmp(
        imgInfo: GanGanOnline.ImgItemInfoMain,
        img?: HTMLImageElement
    ): Promise<HTMLImageElement> {
        const relName = this.getPicRelName(imgInfo.imgIndex);
        const parsedRelName = relName + ".parsed.jpg";
        const localRelName = joinPath(getAppDirPath(), "tmp", relName);
        const localParsedRelName = joinPath(getAppDirPath(), "tmp", parsedRelName);
        const parsedSrc = "akaba:///tmp/" + parsedRelName;
        return new Promise<HTMLImageElement>((resolve, reject) => {
            super.loadImgFromTmp(imgInfo, img)
                .finally(() => {
                    this.writeParsedTmp(imgInfo, localRelName, localParsedRelName)
                        .then(() => {
                            this.buildImgFrom(parsedSrc, imgInfo.type, img)
                                .then((imgElm) => {
                                    return resolve(imgElm);
                                })
                                .catch((err) => {
                                    reject(err);
                                });
                        })
                        .catch((err) => {
                            reject(err);
                        });
                });
        });
    }
    protected async writeParsedTmp(
        imgInfo: GanGanOnline.ImgItemInfoMain,
        relName: string,
        parsedSrc?: string
    ): Promise<void> {
        const originData = await readFile(relName, null);
        const newData = this.parseOriginData(imgInfo, originData as any as ArrayBuffer);
        if (!parsedSrc) {
            parsedSrc = relName + ".parsed.jpg";
        }
        await writeFile(parsedSrc, newData, null);
    }
    protected parseOriginData(imgInfo: GanGanOnline.ImgItemInfoMain, data: ArrayBuffer) {
        const rawList = new Uint8Array(data);
        const keyList = new Uint8Array(
            imgInfo.secretKey
                .match(/.{1,2}/g)
                .map((e) => {
                    return parseInt(e, 16);
                })
        );

        return rawList.map((rawItem, index) => {
            // tslint:disable-next-line:no-bitwise
            return rawItem ^ keyList[index % keyList.length];
        });
    }
}
